#pragma once

#include <vector>              // 用于存储工作线程
#include <queue>               // 用于实现任务队列
#include <memory>              // 智能指针
#include <thread>              // C++11线程库
#include <mutex>               // 互斥锁，保证线程安全
#include <condition_variable>  // 条件变量，用于线程通信
#include <future>              // 异步任务结果
#include <functional>          // std::function，用于封装任务
#include <stdexcept>           // 标准异常
#include <atomic>              // 原子操作，线程安全的变量
#include <unordered_set>
#include <unordered_map>

#include "Logger.h"
#include "TaskInfo.h"
#include "ThreadPoolMetrics.h"

class ThreadPool {
public:
    // 构造函数，创建指定数量的工作线程
    ThreadPool(size_t threads, LogLevel logLevel = LogLevel::INFO, bool consoleLog = true, const std::string& logFile = "");
    
    // 禁用拷贝构造函数和赋值操作符
    ThreadPool(const ThreadPool&) = delete;
    ThreadPool& operator=(const ThreadPool&) = delete;
    
    // 析构函数
    ~ThreadPool();

    // 提交任务（模板不支持分离编译）
    template<class F, class... Args>
    auto enqueue(F&& f, Args&&... args)->std::future<typename std::invoke_result<F, Args...>::type>;

    // 带优先级的任务提交(可选超时参数)
    template<class F, class... Args>
    auto enqueueWithPriority(TaskPriority priority, std::chrono::milliseconds timeout, F&& f, Args&&... args)
    -> std::future<typename std::invoke_result<F, Args...>::type>;

    // 批量提交任务(可选超时参数)
    template<class F>
    std::vector<std::future<void>> enqueueMany(const std::vector<F>& tasks,
                                               TaskPriority priority = TaskPriority::MEDIUM,
                                               std::chrono::milliseconds timeout = std::chrono::milliseconds(0));

    // 带任务ID前缀的批量提交任务(可选超时参数)
    template<class F>
    std::vector<std::future<void>> enqueueManyWithIdPrefix(const std::string& idPrefix,
                                                           const std::string& descriptionPrefix,
                                                           const std::vector<F>& tasks,
                                                           TaskPriority priority = TaskPriority::MEDIUM,
                                                           std::chrono::milliseconds timeout = std::chrono::milliseconds(0));
    

    // 带id和任务描述的任务提交
    template<class F, class... Args>
    auto enqueueWithInfo(std::string taskId, std::string description, TaskPriority priority, std::chrono::milliseconds timeout, F&& f, Args&&... args)
    -> std::future<typename std::invoke_result<F, Args...>::type>;

    // 设置最大线程数
    void setMaxThreads(size_t max);

    // 设置最大线程数
    size_t getMaxThreads() const;

    // 获取线程池中的线程数量
    size_t getThreadCount() const;

    // 获取任务队列中等待执行的任务数量
    size_t getTaskCount();

    // 获取已经完成的任务数量
    size_t getCompletedTaskCount() const;

    // 获取活跃线程数量
    size_t getActiveThreadCount() const;

    // 获取等待的线程数
    size_t getWaitingThreadCount() const;

    // 获取失败得任务数量
    size_t getFailedTaskCount() const;

    // 取消指定ID的任务
    bool cancelTask(const std::string& taskId);

    // 动态调整线程池大小
    void resize(size_t threads);

    // 暂停线程池
    void pause();

    // 恢复线程池
    void resume();

    // 等待所有任务完成
    void waitForTasks();

    // 清空任务队列
    void clearTasks();

    // 获取性能报告
    std::string getMetricsReport() const;

    // 设置日志级别
    void setLogLevel(LogLevel level);

    // 状态查询方法
    bool isStoped() const
    {
        return stop;
    }

    // 获取任务状态
    TaskStatus getTaskStatus(const std::string& taskId);

    // 获取任务状态字符串
    std::string getTaskStatusString(const std::string& taskId);


private:
    // 工作线程 - 线程池的核心逻辑
    void workerThread(size_t id);

    // 工作线程功能
    TaskFetchResult getNextTask(size_t id, std::shared_ptr<TaskInfo>& taskPtr);
    void executeTask(size_t id, std::shared_ptr<TaskInfo> taskPtr);
    void executeTaskWithTimeout(std::shared_ptr<TaskInfo> taskPtr, bool& isTimeout);

    void handleTaskException(std::shared_ptr<TaskInfo> taskPtr, const std::string& errorMessage, bool isTimeout);
    void cleanupTask(std::shared_ptr<TaskInfo> taskPtr);
    void logTaskCompletion(size_t id, std::shared_ptr<TaskInfo>  taskPtr, const std::chrono::nanoseconds& duration);


    // 创建任务函数
    template<class F, class... Args>
    auto createTaskFunction(std::shared_ptr<std::promise<typename std::invoke_result<F, Args...>::type>> promise, F&& f, Args&&... args)
    -> std::function<void()>;
    
    // 记录任务提交日志
    void logTaskSubmission(const std::string& taskId, const std::string& description, TaskPriority priority, std::chrono::milliseconds timeout);

    // 检查并创建任务信息
    std::shared_ptr<TaskInfo> checkAndCreateTaskInfo(const std::string& taskId,
                                                     const std::string& description,
                                                     TaskPriority priority,
                                                     std::chrono::milliseconds timeout,
                                                     std::function<void()> taskFunction);
    
private:
    // 存储需要停止的线程id
    std::unordered_set<size_t> threadsToStop;

    // 工作线程容器
    std::vector<std::thread> workers;
    
    // 任务队列
    // std::queue<std::function<void()>> tasks;
    std::priority_queue<TaskInfo> tasks;

    // 任务id映射表:  任务id->任务信息的共享指针
    std::unordered_map<std::string, std::shared_ptr<TaskInfo>> taskIdMap;
    
    // 同步机制
    std::mutex queue_mutex;
    std::condition_variable condition;
    std::condition_variable waitCondition;
    
    // 控制线程池状态
    std::atomic<bool> stop{false};
    std::atomic<bool> paused{false};

    // 最大线程数限制
    size_t maxThreads;

    // 日志系统
    Logger logger;

    // 性能指标
    ThreadPoolMetrics metrics;
};


// 模板函数实现
#include "ThreadPool.inl"

// template<class F, class... Args>
// auto ThreadPool::enqueue(F&& f, Args&&... args)->std::future<typename std::invoke_result<F, Args...>::type>
// {
//     // 一、获取任务的返回类型
//     using return_type = typename std::invoke_result<F, Args...>::type;

//     // 二、将任务包装成 无参无返 的类型
//     /**
//      * 简介: std::packaged_task 是C++11引入的一个类模板
//      * 
//      * 语法：std::packaged_task<ReturnType(ArgTypes...)>
//      * std::packaged_task的模板参数必须为完整的函数签名
//      * 
//      * 功能: 包装一个可调用对象，并将其执行结果与一个std::future对象关联起来，使得异步获取任务执行结果变得简单。
//      * 1.它包装了一个可调用对象
//      * 2.当调用packaged_task对象时，实际上是在调用被包装的可调用对象
//      * 3.它自动将调用结果存储在一个共享状态中
//      * 4.通过get_future()方法可以获取一个future对象，用于异步获取结果
//      * 
//      * 注意:
//      * 1.packaged_task是不可拷贝的，但可以移动
//      * 2.get_future()只能调用一次，多次调用会抛出std::future_error
//      * 3.如果packaged_task被销毁而关联的future还未获取结果，则future会抛出异常
//      * 4.与std::async相比，packaged_task提供了更多的控制权，但需要手动管理线程
//      * 
//      * 拓展:
//      * 1. std::packaged_task 和 std::bind 的返回对象都是 只能移动（move-only） 的类型:
//      * std::bind 返回的是一个未指定类型的可调用对象（通常是一个内部绑定器类型），它 不能拷贝，但可以移动。
//      * std::packaged_task 也是不可拷贝的（它的拷贝构造函数和拷贝赋值运算符被删除），只能移动。
//      * 2. std::move 的作用:
//      * std::move(bindedFunc) 将 bindedFunc 转换成一个右值引用，使得它可以被移动构造或移动赋值，而不是尝试拷贝（会导致编译错误）。
//      */
//     // auto task = std::make_shared<std::packaged_task<return_type()>>(
//     // std::bind(std::forward<F>(f), std::forward<Args>(args)...)
//     // );
//     // 下面这三行代码效果同上!!!
//     auto bindedFunc = std::bind(std::forward<F>(f), std::forward<Args>(args)...);
//     std::packaged_task<return_type()> packagedTask(std::move(bindedFunc));
//     auto taskPtr = std::make_shared<std::packaged_task<return_type()>>(std::move(packagedTask));

//     // 三、获取保存任务异步处理结果的future
//     std::future<return_type> result = taskPtr->get_future();

//     // 四、将任务提交到队列中(加锁保护)
//     {
//         // 1.加锁保护
//         std::unique_lock<std::mutex> lock(this->queue_mutex);
//         // 2.检查线程池是否停止
//         if(this->stop){
//             throw std::runtime_error("enqueue on stoped ThreadPool");
//         }
//         // 3.线程池未停止，提交任务
//         this->tasks.emplace([taskPtr](){
//             (*taskPtr)();
//         });
//         // 4.唤醒正在等待的工作线程
//         this->condition.notify_one();
//     }
//         // 五、返回future，让调用者能够获取异步返回的结果
//     return result;
// }
